package com.example.gateway.filter;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.example.common.constent.JWTConstent;
import com.example.common.constent.RequestHeaders;
import com.example.common.vo.Result;
import io.netty.util.internal.StringUtil;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

@Component
@Order(100)
public class LoginFilter implements GlobalFilter {

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //如果是登陆请求就直接放行
        if(exchange.getRequest().getPath().toString().equals("/system/login") ||exchange.getRequest().getPath().toString().equals("/v3/api-docs")){
            return chain.filter(exchange);
        }
        List<String> tokenList = exchange.getRequest().getHeaders().get(RequestHeaders.LOGIN_TOKEN);

        ServerHttpResponse response = exchange.getResponse();

        if(tokenList == null|| tokenList.size()!=1|| StringUtil.isNullOrEmpty(tokenList.get(0))){
            //返回TOKEN_ERROR_CODE表示token异常，前端会跳到登陆页面
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            String errorMessage = JSONUtil.toJsonStr(Result.fail(JWTConstent.TOKEN_ERROR_CODE, "用户未登录", null));
            //验证失败就直接返回，不向下交付了
            return response.writeWith(Mono.just(response.bufferFactory().wrap(errorMessage.getBytes())));
        }
        String token = tokenList.get(0);

        boolean verify = JWTUtil.verify(token, JWTConstent.JWT_KEY.getBytes());

        //如果验证失败
        if(!verify){
            //返回TOKEN_ERROR_CODE表示token异常，前端会跳到登陆页面
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            String errorMessage = JSONUtil.toJsonStr(Result.fail(JWTConstent.TOKEN_ERROR_CODE, "token验证异常", null));
            //验证失败就直接返回，不向下交付了
            return response.writeWith(Mono.just(response.bufferFactory().wrap(errorMessage.getBytes())));
        }
        //验证token是否过期
        JWT jwt = JWTUtil.parseToken(token);
        String expireTimeString = (String) jwt.getPayload(JWTConstent.EXPIRE_TIME);
        Long expireTime =Long.parseUnsignedLong(expireTimeString);
        DateTime dateTime = new DateTime(expireTime);
        //如果token过期了
        if(dateTime.isBefore(DateTime.now())){
            //返回TOKEN_ERROR_CODE表示token异常，前端会跳到登陆页面
            response.getHeaders().setContentType(MediaType.APPLICATION_JSON);
            String errorMessage = JSONUtil.toJsonStr(Result.fail(JWTConstent.TOKEN_ERROR_CODE, "token已过期", null));
            //验证失败就直接返回，不向下交付了
            return response.writeWith(Mono.just(response.bufferFactory().wrap(errorMessage.getBytes())));
        }
        //验证成功，又没过期，则续期，放行
        jwt.setPayload(JWTPayload.EXPIRES_AT, DateTime.now().offsetNew(DateField.MINUTE, JWTConstent.JWT_CONTINUE_TIME));
        String newToken = JWTUtil.createToken(jwt.getPayloads(), JWTConstent.JWT_KEY.getBytes());
        exchange.getRequest().mutate().header(RequestHeaders.LOGIN_TOKEN, newToken).build();
        return chain.filter(exchange);

    }

}
